#include <iostream>
using namespace std;
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <vector>
#include <time.h>
#include <string>

void makeseek()
{
    srand((unsigned int)time(nullptr));
}

#define PROCESS_NUM 5

typedef void (*func_t)();

void downloadtask()
{
    cout << getpid() << "下载任务" << endl;
    sleep(1);
}
void iotask()
{
    cout << getpid() << "io任务" << endl;
    sleep(1);
}
void nettask()
{
    cout << getpid() << "网络任务" << endl;
    sleep(1);
}
void fflusttask()
{
    cout << getpid() << "刷新任务" << endl;
    sleep(1);
}

void LoadTask(vector<func_t> *taskmap)
{
    assert(taskmap);
    taskmap->push_back(downloadtask);
    taskmap->push_back(iotask);
    taskmap->push_back(nettask);
    taskmap->push_back(fflusttask);
}

class subEp
{
public:
    subEp(int &writefd, pid_t &subid) : _writefd(writefd), _subid(subid)
    {
        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "%d号进程:[pid:%d,fd:%d]", _num++, getpid(), _writefd);
        _name = buffer;
    }
    ~subEp()
    {
    }

public:
    int _writefd;
    string _name;
    pid_t _subid;

    static int _num;
};
int subEp::_num = 0;

// 接收4个字节的命令码
int recvfrom(int readfd)
{
    int code = 0;
    ssize_t s = read(readfd, &code, sizeof(code));
    assert(s == sizeof(int));
    return code;
}

void CreateProcess(vector<subEp> *subs, vector<func_t> &taskmap)
{
    for (int i = 0; i < PROCESS_NUM; i++)
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void)n;
        pid_t id = fork();
        if (id == 0)
        {
            // 子进程
            close(fds[1]);
            // 接收命令
            while (true)
            {
                int commandcode = recvfrom(fds[0]);
                // 任务列表的范围
                if (commandcode >= 0 && commandcode < taskmap.size())
                {
                    taskmap[commandcode](); // 回调函数
                }
                else
                {
                    cout << "接收命令失败" << endl;
                }
            }

            exit(0);
        }

        // 父进程
        close(fds[0]);
        subEp sub(fds[1], id); // 构建对象
        subs->push_back(sub);
    }
}

void sendTask(const subEp &process, int taskIndex)
{
    cout << "send task num:" << taskIndex << "send to->" << process._name << endl;
    // 发送4个字节作为命令
    int n = write(process._writefd, &taskIndex, sizeof(taskIndex));
    assert(n == sizeof(int));
    (void)n;
}

void LoadBlance(const vector<subEp> &subs, const vector<func_t> &taskmap, int &taskcnt)
{
    int process_num = subs.size(); // 子进程的数量
    int task_num = taskmap.size(); // 任务的数量
    // bool quit = false;
    bool forever = taskcnt == 0 ? true : false;
    while (1)
    {
        int subIndex = rand() % process_num;
        int taskIndex = rand() % task_num;

        sendTask(subs[subIndex], subIndex);
        sleep(1);
        if (!forever)
        {
            taskcnt--;
            if (taskcnt == 0)
                break;
        }
    }
    // 一般用完以后都把文件描述符关闭
    // 关闭写文件描述符
    for (int i = 0; i < subs.size(); i++)
    {
        close(subs[i]._writefd);
    }
}

void waitprocess(vector<subEp> &process)
{
    int processnum = process.size();
    for (int i = 0; i < processnum; i++)
    {
        waitpid(process[i]._subid, nullptr, 0);
        cout << "wait sub process success..." << process[i]._subid << endl;
    }
}
// 基于匿名管道的多进程池
int main()
{
    makeseek();
    vector<func_t> taskmap;
    LoadTask(&taskmap);

    vector<subEp> subs;
    CreateProcess(&subs, taskmap);

    // 从这里往下都是父进程
    int taskcnt = 20;
    LoadBlance(subs, taskmap, taskcnt);
    
    waitprocess(subs);
    return 0;
}
